package com.rangers.game.team.demo;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import javax.annotation.Nullable;

/**
 * 王者荣耀的组队游戏的demo
 * 
 * @author vencano
 * @date 2018年3月17日
 */
public class WzryDemo {

	/**
	 * 6人，10s 开局，overgame;
	 * 
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {

		AtomicInteger teamNum = new AtomicInteger(1000);
		List<String> players = Arrays.asList("玩家A","玩家B","玩家C","玩家D","玩家E","玩家F");
		
		GameTeamThread round1 = new GameTeamThread(players, teamNum.incrementAndGet());
		round1.readyOne("玩家A");
		round1.readyOne("玩家C");
		round1.readyOne("玩家E");
		round1.readyOne("玩家F");
		Thread.sleep(4000);
		round1.readyOne("玩家D");

		GameTeamThread round2 = new GameTeamThread(players, teamNum.incrementAndGet());
		GameTeamThread round3 = new GameTeamThread(players, teamNum.incrementAndGet());
		players.stream().forEach(name -> round2.readyOne(name));
		players.stream().forEach(name -> round3.readyOne(name));
		Thread.sleep(12000);
		round2.game.overgame();
		Thread.sleep(3000);
		round3.game.overgame();
	}

	/**
	 * 组队线程
	 * @author vencano
	 * @date 2018年3月17日
	 */
	public static class GameTeamThread extends Thread {
		
		public final int playerNumSet = 6; //玩家人数设定
		
		public final long recordTimesSet = 10; //倒计时设定
		
		private volatile boolean teamBegin = true;// 开始组队

		private volatile boolean teamStatus = false;// 是否组队成功

		private Map<String, Boolean> playersMap = new LinkedHashMap<>(playerNumSet);

		private long startTime = System.currentTimeMillis();

		private GamePlayingThread game;

		private String name = Thread.currentThread().getName();

		private final static String TEAM_NAME_PREFIX = "T-";

		private AtomicInteger roomNum = new AtomicInteger(10000);

		public GameTeamThread(@Nullable List<String> players, int teamNum) {
			this.name = TEAM_NAME_PREFIX + teamNum;
			playersMap = players.stream().collect(Collectors.toMap(a -> a, b -> false));
			this.start();
		}

		/**
		 * 玩家确认 
		 */
		public void readyOne(String playername) {
			playersMap.computeIfPresent(playername, (k, v) -> true);
		}

		private boolean isAllReady() {
			long recordTimes = (System.currentTimeMillis() - startTime) / 1000;
			return recordTimes <= recordTimesSet && !playersMap.values().contains(false);
		}

		@Override
		public void run() {
			try {
				while (teamBegin) {
					sleep(2000);
					long recordTimes = (System.currentTimeMillis() - startTime) / 1000;
					if (teamStatus) {
						System.err.println(this.name + "：组队成功，开始游戏");
						this.game = new GamePlayingThread(this.name, roomNum.incrementAndGet());
						game.start();
						break;
					} else {
						if (recordTimes > recordTimesSet) {
							this.teamBegin = false;
							System.err.println(this.name + "：组队失败，有玩家未确认");
							break;
						}
						if (isAllReady()) {
							this.teamStatus = true;
						}
					}
					System.out.println(this.name + "用时：" + recordTimes + "s,->组队信息：" + this.playersMap.toString());
				}
			} catch (InterruptedException ex) {
				// 结束
				System.err.println(this.name + "：组队进程中断");
			}
		}

		public void stopTeamBegin() {
			this.teamBegin = false;
			synchronized (this) {
				notifyAll();
			}
		}
	}

	/**
	 * 游戏线程
	 * @author vencano
	 * @date 2018年3月17日
	 */
	public static class GamePlayingThread extends Thread {

		private volatile boolean overgame;// volatile并发可见性，保证同一时刻只有一个线程修改该变量

		private long startTime = System.currentTimeMillis();

		private String name = Thread.currentThread().getName();

		private final static String ROOM_NAME_PREFIX = "R-";

		public GamePlayingThread(String teamname, int roomNum) {
			this.name = ROOM_NAME_PREFIX + roomNum + "(" + teamname + ")";
		}

		@Override
		public void run() {
			try {
				while (!overgame) {
					synchronized (this) {
						wait(2000);
						System.out.println(this.name + "：游戏 ing...");
					}
				}
			} catch (InterruptedException ex) {
				// 结束
				System.err.println(this.name + ":game interrupted !");
			} finally {
				long recordTimes = (System.currentTimeMillis() - startTime) / 1000;
				System.err.println(this.name + ":game over !,用时：" + recordTimes + "s");
			}
		}

		public void overgame() {
			this.overgame = true;
			synchronized (this) {
				notifyAll();
			}
		}
	}

}
